home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / sw / control.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  50.0 KB  |  1,896 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. #include "sw.h"
  18. #include "extern.h"
  19. #include "control.h"
  20. #include "main.h"
  21. #include "ship.h"
  22. #include "hud.h"
  23. #include "resources.h"
  24. #include "universe.h"
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <Xm/Form.h>
  29. #include <Xm/RowColumn.h>
  30. #include <Xm/LabelG.h>
  31. #include <Xm/Frame.h>
  32. #include <Xm/PushBG.h>
  33. #include <Xm/ToggleBG.h>
  34. #include <Xm/ArrowBG.h>
  35. #include <Xm/Text.h>
  36. #include <Xm/ScrolledW.h>
  37. #include <X11/keysym.h>
  38. #include <X11/Xirisw/GlxMDraw.h>
  39. #include <gl/gl.h>
  40. #include <gl/glws.h>
  41.  
  42. #define    NORADIO
  43.  
  44. struct GlxSize {
  45.   public:
  46.     Dimension        dx, dy;            // widget size
  47.     void        (*draw)(GlxSize*, int);    // call this to draw
  48.     void        (*resized)(GlxSize*);    // call this when resized
  49.     Widget        w;            // the GlxMDraw widget
  50.     float        x, y;            // widget specific info
  51. };
  52.  
  53. static RadioSetting    radioState;        // radio radio state
  54. static SoundSetting    soundState;        // sound radio state
  55. static char*        msgBuffer;        // current messages;
  56. static Widget        msgText;        // message text widget
  57. static Widget        scoreInfo,        // score display widget
  58.             playersInfo,        // num players display widget
  59.             flagInfo;        // whose flag display widget
  60. static Widget        radioToggle[3],        // radio radio toggle buttons
  61.             soundToggle[3];        // sound radio toggle buttons
  62. static float        thrustLevel[11];    // thrust amounts
  63.  
  64. // GlxMDraw widget draw and resize function prototypes
  65. static void        drawWeapon(GlxSize*, int);
  66. static void        resizeWeapon(GlxSize*);
  67. static void        drawShield(GlxSize*, int);
  68. static void        resizeShield(GlxSize*);
  69. static void        drawLaser(GlxSize*, int);
  70. static void        resizeLaser(GlxSize*);
  71. static void        drawMissile(GlxSize*, int);
  72. static void        resizeMissile(GlxSize*);
  73. static void        drawThrust(GlxSize*, int);
  74. static void        resizeThrust(GlxSize*);
  75. static void        drawFuel(GlxSize*, int);
  76. static void        resizeFuel(GlxSize*);
  77. static void        drawRadar(GlxSize*, int);
  78. static void        resizeRadar(GlxSize*);
  79. static void        drawTarget(GlxSize*, int);
  80. static void        drawTeamColor(GlxSize*, int);
  81. static void             unitInitCallback(Widget w, caddr_t d);
  82. static void             unitResizeCallback(Widget w, caddr_t d, caddr_t cd);
  83. static void             glxDrawCallback(Widget w, caddr_t d, caddr_t);
  84.  
  85. // GlxMDraw widget sizes and resize function prototypes
  86. static GlxSize        weaponSize = { 100, 100, drawWeapon, resizeWeapon },
  87.             shieldSize = { 100, 100, drawShield, resizeShield },
  88.             laserSize = { 1, 1, drawLaser, resizeLaser },
  89.             missileSize = { 1, 1, drawMissile, resizeMissile },
  90.             thrustSize = { 1, 1, drawThrust, resizeThrust },
  91.             fuelSize = { 1, 1, drawFuel, resizeFuel },
  92.             radarSize = { PANELHEIGHT-40, PANELHEIGHT-40,
  93.                         drawRadar, resizeRadar },
  94.             targetSize = { 100, 120, drawTarget, 0 },
  95.             colorSize = { 100, 100, drawTeamColor, 0 };
  96.  
  97. // old state information (to avoid excessive redrawing and computation)
  98. static int        oldShield[6],
  99.             oldLaser,
  100.             oldMissile,
  101.             oldMissileReady,
  102.             oldThrust,
  103.             oldFuel,
  104.             blinkOn,
  105.             oldTargetHeading,
  106.             oldTargetPitch,
  107.             oldTargetDist;
  108. static ShipObject*    oldTarget;
  109. static float        blinkTime;
  110.  
  111. // key state information
  112. static int        thrustKeyPressed[11];
  113.  
  114. //
  115. // Begin control panel callback functions
  116. //
  117.  
  118. //
  119. // general GL callbacks
  120. //
  121.  
  122. static void        unitInitCallback(Widget w, caddr_t d)
  123. {
  124.   GLXwinset(XtDisplay(w), XtWindow(w));
  125.   ortho2(0.0, 1.0, 0.0, 1.0);
  126.   subpixel(TRUE);
  127.   GlxSize* s = (GlxSize*)d;
  128.   if (s) {
  129.     XtVaGetValues(w,
  130.     XmNwidth,    &s->dx,
  131.     XmNheight,    &s->dy,
  132.     NULL);
  133.     if (s->resized) (*s->resized)(s);
  134.   }
  135. }
  136.  
  137. static void        unitResizeCallback(Widget w, caddr_t d, caddr_t cd)
  138. {
  139.   GlxDrawCallbackStruct* calldata = (GlxDrawCallbackStruct*)cd;
  140.   GLXwinset(XtDisplay(w), XtWindow(w));
  141.   viewport(0, (Scoord) calldata->width-1, 0, (Scoord) calldata->height-1);
  142.   ortho2(0.0, 1.0, 0.0, 1.0);
  143.   GlxSize* s = (GlxSize*)d;
  144.   if (s) {
  145.     s->dx = calldata->width;
  146.     s->dy = calldata->height;
  147.     if (s->resized) (*s->resized)(s);
  148.     if (s->draw) (*s->draw)(s, TRUE);
  149.   }
  150. }
  151.  
  152. static void        pixelInitCallback(Widget w, caddr_t d, caddr_t)
  153. {
  154.   GLXwinset(XtDisplay(w), XtWindow(w));
  155.   subpixel(TRUE);
  156.   Dimension dx, dy;
  157.   XtVaGetValues(w,
  158.     XmNwidth,    &dx,
  159.     XmNheight,    &dy,
  160.     NULL);
  161.   ortho2(-0.5, float(dx) - 0.5, -0.5, float(dy) - 0.5);
  162.   GlxSize* s = (GlxSize*)d;
  163.   if (s) {
  164.     s->dx = dx;
  165.     s->dy = dy;
  166.     if (s->resized) (*s->resized)(s);
  167.   }
  168. }
  169.  
  170. static void        pixelResizeCallback(Widget w, caddr_t d, caddr_t cd)
  171. {
  172.   GlxDrawCallbackStruct* calldata = (GlxDrawCallbackStruct*)cd;
  173.   GLXwinset(XtDisplay(w), XtWindow(w));
  174.   viewport(0, (Scoord) calldata->width-1, 0, (Scoord) calldata->height-1);
  175.   ortho2(-0.5, float(calldata->width)-0.5, -0.5, float(calldata->height)-0.5);
  176.   GlxSize* s = (GlxSize*)d;
  177.   if (s) {
  178.     s->dx = calldata->width;
  179.     s->dy = calldata->height;
  180.     if (s->resized) (*s->resized)(s);
  181.     if (s->draw) (*s->draw)(s, TRUE);
  182.   }
  183. }
  184.  
  185. static void        radarInitCallback(Widget w, caddr_t d, caddr_t)
  186. {
  187.   GLXwinset(XtDisplay(w), XtWindow(w));
  188.   ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
  189.   subpixel(TRUE);
  190.   GlxSize* s = (GlxSize*)d;
  191.   if (s) {
  192.     XtVaGetValues(w,
  193.     XmNwidth,    &s->dx,
  194.     XmNheight,    &s->dy,
  195.     NULL);
  196.     if (s->resized) (*s->resized)(s);
  197.   }
  198. }
  199.  
  200. static void        radarResizeCallback(Widget w, caddr_t d, caddr_t cd)
  201. {
  202.   GlxDrawCallbackStruct* calldata = (GlxDrawCallbackStruct*)cd;
  203.   GLXwinset(XtDisplay(w), XtWindow(w));
  204.   viewport(0, (Scoord) calldata->width-1, 0, (Scoord) calldata->height-1);
  205.   ortho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
  206.   GlxSize* s = (GlxSize*)d;
  207.   if (s) {
  208.     s->dx = calldata->width;
  209.     s->dy = calldata->height;
  210.     if (s->resized) (*s->resized)(s);
  211.     if (s->draw) (*s->draw)(s, TRUE);
  212.   }
  213. }
  214.  
  215. static void        glxDrawCallback(Widget w, caddr_t d, caddr_t)
  216. {
  217.   GlxSize* s = (GlxSize*)d;
  218.   if (s && s->draw) (*s->draw)(s, TRUE);
  219.   else {
  220.     GLXwinset(XtDisplay(w), XtWindow(w));
  221.     cpack(0xff000000);
  222.     clear();
  223.   }
  224. }
  225.  
  226. //
  227. // Stylized ship
  228. //
  229.  
  230. static float        stylizedShip[9][2] = {
  231.                 {  0.0,  1.0 },
  232.                 { -0.4, -1.0 },
  233.                 {  0.4, -1.0 },
  234.                 { -0.2,  0.0 },
  235.                 { -0.9, -0.6 },
  236.                 { -1.0, -1.0 },
  237.                 {  0.2,  0.0 },
  238.                 {  0.9, -0.6 },
  239.                 {  1.0, -1.0 } };
  240.  
  241. static void        drawStylizedShip()
  242. {
  243.   bgnclosedline();
  244.     v2f(stylizedShip[0]);
  245.     v2f(stylizedShip[1]);
  246.     v2f(stylizedShip[2]);
  247.   endclosedline();
  248.   bgnline();
  249.     v2f(stylizedShip[3]);
  250.     v2f(stylizedShip[4]);
  251.     v2f(stylizedShip[5]);
  252.     v2f(stylizedShip[1]);
  253.   endline();
  254.   bgnline();
  255.     v2f(stylizedShip[6]);
  256.     v2f(stylizedShip[7]);
  257.     v2f(stylizedShip[8]);
  258.     v2f(stylizedShip[2]);
  259.   endline();
  260. }
  261.  
  262. //
  263. // Weapon callbacks
  264. //
  265.  
  266. static float        laserInfoPos[2] = { 0.0, 1.0 };
  267. static float        missileInfoPos[2][2] =
  268.                 { { -0.5, -0.5 }, { 0.5, -0.5 } };
  269.  
  270. static void        drawWeapon(GlxSize* s, int)
  271. {
  272.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  273.   cpack(0xff000000);
  274.   clear();
  275.   cpack(0xff808080);
  276.   pushmatrix();
  277.     translate(0.5, 0.50, 0.0);
  278.     scale(0.25, 0.25, 0.25);
  279.     drawStylizedShip();
  280.  
  281.     // draw laser
  282.     if (currentWeapon() == Laser) cpack(0xff00ff00);
  283.     else cpack(0xff808080);
  284.     sboxf(laserInfoPos[0] - 12.0*s->x, laserInfoPos[1] - 12.0*s->y,
  285.     laserInfoPos[0] + 12.0*s->x, laserInfoPos[1] + 12.0*s->y);
  286.  
  287.     // draw missiles
  288.     if (currentWeapon() == Missile) cpack(0xff00ff00);
  289.     else cpack(0xff808080);
  290.     for (int i = 0; i < 2; i++)
  291.       sboxf(missileInfoPos[i][0] - 4.0*s->x, missileInfoPos[i][1] - 0.5,
  292.         missileInfoPos[i][0] + 4.0*s->x, missileInfoPos[i][1] + 0.5);
  293.   popmatrix();
  294.  
  295.   // show weapon name
  296.   font(0);
  297.   cpack(0xffc0c0c0);
  298.   cmov2(4.0 * s->x, float(getdescender() + 1) * s->y);
  299.   charstr(weaponName(currentWeapon()));
  300. }
  301.  
  302. static void        resizeWeapon(GlxSize* s)
  303. {
  304.   s->x = 1.0 / float(s->dx);
  305.   s->y = 1.0 / float(s->dy);
  306. }
  307.  
  308. static void        inputWeapon(Widget, caddr_t d, caddr_t cd)
  309. {
  310.   // if it's a left button press, select weapon mouse is nearer
  311.   GlxDrawCallbackStruct* calldata = (GlxDrawCallbackStruct*)cd;
  312.   if (calldata->event->xany.type == ButtonPress &&
  313.     calldata->event->xbutton.button == Button1) {
  314.     // very simple check -- if in upper part select laser else missiles
  315.     GlxSize* s = (GlxSize*)d;
  316.     if (calldata->event->xbutton.y < int(0.5 * float(s->dy))) {
  317.       currentWeapon(Laser);
  318.     }
  319.     else {
  320.       currentWeapon(Missile);
  321.     }
  322.   }
  323. }
  324.  
  325. //
  326. // Shield callbacks
  327. //
  328.  
  329. static short        shieldInfoPos[6][2];
  330. static short        shieldInfoSize[2];
  331.  
  332. static void        drawShield(GlxSize* s, int forced)
  333. {
  334.   int strengthChanges = 0, strength[6];
  335.   // get strengths and see if they've changed
  336.   for (int i = ShipObject::FrontShield; i <= ShipObject::BottomShield; i++) {
  337.     strength[i] = int(20.0 * myShip->shipInfo().shieldStrength[i] + 0.5);
  338.     if (oldShield[i] != strength[i]) strengthChanges++;
  339.   }
  340.   if (!forced && strengthChanges == 0) return;    // no difference
  341.  
  342.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  343.   if (forced || strengthChanges == 6) {        // redraw whole thing
  344.     cpack(0xff000000);
  345.     clear();
  346.     cpack(0xff808080);
  347.     pushmatrix();
  348.       translate(float(s->dx >> 1), float(s->dy >> 1), 0.0);
  349.       // keep scale uniform so the ship isn't distorted
  350.       scale(0.25 * float(s->dx), 0.25 * float(s->dx), 0.25 * float(s->dx));
  351.       drawStylizedShip();
  352.     popmatrix();
  353.   }
  354.  
  355.   for (i = ShipObject::FrontShield; i <= ShipObject::BottomShield; i++) {
  356.     if (!forced && oldShield[i] == strength[i]) continue;
  357.  
  358.     // record new strength
  359.     oldShield[i] = strength[i];
  360.  
  361.     // set color according to remaining strength
  362.     if (strength[i] < 3) cpack(0xff0000ff);
  363.     else if (strength[i] < 6) cpack(0xff00dddd);
  364.     else cpack(0xff00bb00);
  365.  
  366.     // draw box
  367.     if (strength[i] == 0 && blinkOn) {        // solid warning bar
  368.       sboxfs(shieldInfoPos[i][0], shieldInfoPos[i][1] - 1,
  369.         shieldInfoPos[i][0] + shieldInfoSize[0] - 1,
  370.         shieldInfoPos[i][1] + shieldInfoSize[1]);
  371.       continue;
  372.     }
  373.     sboxs(shieldInfoPos[i][0], shieldInfoPos[i][1] - 1,
  374.         shieldInfoPos[i][0] + shieldInfoSize[0] - 1,
  375.         shieldInfoPos[i][1] + shieldInfoSize[1]);
  376.  
  377.     // draw shield strength meter
  378.     for (int j = 0; j < strength[i]; j++)
  379.       sboxfs(shieldInfoPos[i][0] + 1,
  380.         shieldInfoPos[i][1] + (Scoord)(float(j) * s->y + 0.5),
  381.         shieldInfoPos[i][0] + shieldInfoSize[0] - 2,
  382.         shieldInfoPos[i][1] + (Scoord)(float(j+1) * s->y + 0.5) - 1);
  383.  
  384.     // clear remaining space in meter
  385.     cpack(0xff000000);
  386.     for (; j < 20; j++)
  387.       sboxfs(shieldInfoPos[i][0] + 1,
  388.         shieldInfoPos[i][1] + (Scoord)(float(j) * s->y + 0.5),
  389.         shieldInfoPos[i][0] + shieldInfoSize[0] - 2,
  390.         shieldInfoPos[i][1] + (Scoord)(float(j+1) * s->y + 0.5) - 1);
  391.   }
  392. }
  393.  
  394. static void        resizeShield(GlxSize* s)
  395. {
  396.   shieldInfoSize[0] = 12;
  397.   shieldInfoSize[1] = short(0.25 * float(s->dx) + 0.5);
  398.  
  399.   s->y = float(shieldInfoSize[1]) / 20.0;
  400.  
  401.   shieldInfoPos[ShipObject::FrontShield][0] = (s->dx - shieldInfoSize[0]) >> 1;
  402.   shieldInfoPos[ShipObject::FrontShield][1] = s->dy - shieldInfoSize[1] - 4;
  403.  
  404.   shieldInfoPos[ShipObject::RearShield][0] = (s->dx - shieldInfoSize[0]) >> 1;
  405.   shieldInfoPos[ShipObject::RearShield][1] = 4;
  406.  
  407.   shieldInfoPos[ShipObject::TopShield][0] = s->dx - shieldInfoSize[0] - 4;
  408.   shieldInfoPos[ShipObject::TopShield][1] = s->dy - shieldInfoSize[1] - 4;
  409.  
  410.   shieldInfoPos[ShipObject::BottomShield][0] = 4;
  411.   shieldInfoPos[ShipObject::BottomShield][1] = 4;
  412.  
  413.   shieldInfoPos[ShipObject::LeftShield][0] =
  414.             shieldInfoPos[ShipObject::BottomShield][0] +
  415.             ((shieldInfoPos[ShipObject::RearShield][0] -
  416.               shieldInfoPos[ShipObject::BottomShield][0]) >> 1);
  417.   shieldInfoPos[ShipObject::LeftShield][1] = (s->dy - shieldInfoSize[1]) >> 1;
  418.  
  419.   shieldInfoPos[ShipObject::RightShield][0] =
  420.             shieldInfoPos[ShipObject::FrontShield][0] +
  421.             ((shieldInfoPos[ShipObject::TopShield][0] -
  422.               shieldInfoPos[ShipObject::FrontShield][0]) >> 1);
  423.   shieldInfoPos[ShipObject::RightShield][1] = (s->dy - shieldInfoSize[1]) >> 1;
  424. }
  425.  
  426. //
  427. // Laser callbacks
  428. //
  429.  
  430. static void        drawLaser(GlxSize* s, int forced)
  431. {
  432.   int t = int(10.0 * (0.1 + 0.7 * myShip->laserHeat()));
  433.   if (t < 0) t = 0;
  434.   else if (t > 10) t = 10;
  435.   if (!forced && t == oldLaser) return;    // not enough difference
  436.   oldLaser = t;
  437.  
  438.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  439.   cpack(0xff000000);
  440.   clear();
  441.   for (int i = 0; i < t; i++) {
  442.     if (i == 0) cpack(0xff00bb00);
  443.     else if (i == 5) cpack(0xff00dddd);
  444.     else if (i == 7) cpack(0xff0000ff);
  445.     sboxfs((Scoord)(float(i) * s->x + 0.5), 0,
  446.     (Scoord)(float(i+1) * s->x + 0.5) - 2, s->dy-1);
  447.   }
  448. }
  449.  
  450. static void        resizeLaser(GlxSize* s)
  451. {
  452.   s->x = float(s->dx) / 10.0;
  453. }
  454.  
  455. //
  456. // Missile callbacks
  457. //
  458.  
  459. static void        drawMissile(GlxSize* s, int forced)
  460. {
  461.   int t = myShip->numMissiles();
  462.   if (t < 0) t = 0;
  463.   else if (t > 16) t = 16;
  464.   int tr = myShip->missileReady();
  465.   if (!forced && t == oldMissile && tr == oldMissileReady)
  466.     return;                    // no difference
  467.   oldMissile = t;
  468.   oldMissileReady = tr;
  469.  
  470.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  471.   cpack(0xff000000);
  472.   clear();
  473.   if (tr) cpack(0xff00bb00);
  474.   else cpack(0xff00dddd);
  475.   for (int i = 0; i < t && i < 15; i++)
  476.     sboxfs((Scoord)(float(i) * s->x + 0.5), 0,
  477.     (Scoord)(float(i+1) * s->x + 0.5) - 2, s->dy-1);
  478.   if (t == 16) {
  479.     Scoord v[2];
  480.     bgnpolygon();
  481.       v[0] = (Scoord)(float(i) * s->x + 0.5); v[1] = s->dy-1; v2s(v);
  482.       v[1] = 0; v2s(v);
  483.       v[0] += 9; v[1] = s->dy >> 1; v2s(v);
  484.     endpolygon();
  485.   }
  486. }
  487.  
  488. static void        resizeMissile(GlxSize* s)
  489. {
  490.   s->x = float(s->dx - 10) / 15.0;
  491. }
  492.  
  493. //
  494. // Thrust callbacks
  495. //
  496.  
  497. static void        drawThrust(GlxSize* s, int forced)
  498. {
  499.   int t = int(10.0 * myShip->engineOutput() + 0.5);
  500.   if (t < -10) t = -10;
  501.   else if (t > 10) t = 10;
  502.   if (!forced && t == oldThrust) return;    // no difference
  503.   oldThrust = t;
  504.  
  505.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  506.   cpack(0xff000000);
  507.   clear();
  508.   if (t >= 0)
  509.     cpack(0xff00bb00);
  510.   else
  511.     cpack(0xff0000bb);
  512.   for (int i = 0; i < abs(t); i++)
  513.     sboxfs((Scoord)(float(i) * s->x + 0.5), 0,
  514.     (Scoord)(float(i+1) * s->x + 0.5) - 2, s->dy-1);
  515. }
  516.  
  517. static void        resizeThrust(GlxSize* s)
  518. {
  519.   s->x = float(s->dx) / 10.0;
  520. }
  521.  
  522. //
  523. // Fuel callbacks
  524. //
  525.  
  526. static void        drawFuel(GlxSize* s, int forced)
  527. {
  528.   int t = int(20.0 * myShip->fuelLeft() + 0.5);
  529.   if (t < 0) t = 0;
  530.   else if (t > 20) t = 20;
  531.   if (!forced && t == oldFuel) return;        // no difference
  532.   oldFuel = t;
  533.  
  534.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  535.   cpack(0xff000000);
  536.   clear();
  537.   if (t > 7) cpack(0xff00bb00);
  538.   else if (t > 3) cpack(0xff00dddd);
  539.   else cpack(0xff0000ff);
  540.   for (int i = 0; i < t; i++)
  541.     sboxfs((Scoord)(float(i) * s->x + 0.5), 0,
  542.     (Scoord)(float(i+1) * s->x + 0.5) - 2, s->dy-1);
  543. }
  544.  
  545. static void        resizeFuel(GlxSize* s)
  546. {
  547.   s->x = float(s->dx) / 20.0;
  548. }
  549.  
  550. //
  551. // Radio callbacks
  552. //
  553.  
  554. static void        radioChanged(Widget, caddr_t u,
  555.                     XmToggleButtonCallbackStruct* b)
  556. {
  557.   if (b->reason == XmCR_VALUE_CHANGED && b->set)
  558.     radioState = RadioSetting(u);
  559. }
  560.  
  561. //
  562. // Sound callbacks
  563. //
  564.  
  565. static void        soundChanged(Widget, caddr_t u,
  566.                     XmToggleButtonCallbackStruct* b)
  567. {
  568.   if (b->reason == XmCR_VALUE_CHANGED && b->set)
  569.     soundState = SoundSetting(u);
  570. }
  571.  
  572. //
  573. // Radar callbacks
  574. //
  575.  
  576. static void        radarRangeChanged(Widget, caddr_t u,
  577.                     XmArrowButtonCallbackStruct* b)
  578. {
  579.   if (b->reason == XmCR_ACTIVATE) {
  580.     switch (int(u)) {
  581.       case 0: decreaseRange(); break;
  582.       case 1: increaseRange(); break;
  583.     }
  584.   }
  585. }
  586.  
  587. static void        drawRadar(GlxSize* s, int)
  588. {
  589.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  590.   cpack(0xff000000);
  591.   clear();
  592.   zclear();
  593.  
  594.   // draw radar objects
  595.   ShipObject* ship, *targ;
  596.   targ = (currentTarget() == -1) ? NULL : getTarget(currentTarget());
  597.   float r = 1.0 / radarRange();
  598.   float x = s->x / r, y = s->y / r;
  599.  
  600.   pushmatrix();
  601.     scale(r, r, r);
  602.  
  603.     // draw all ships and missiles
  604.     for (int i = 0; i < numberPlayers(); i++) {
  605.       ship = getPlayer(i);
  606.       ShipInfo& info = ship->shipInfo();
  607.       if (ship->active() != ObjectActive) continue;
  608.       if (i != 0) {
  609.     cpack(teamColor(ship->team()));
  610.     pushmatrix();
  611.       translate(playerView[i][0].lp[0], -playerView[i][0].lp[2],
  612.                         playerView[i][0].lp[1]);
  613.       if (playerView[i][0].lp[1] < 0.0)
  614.         rectf(-x, -y, x, y);
  615.       else
  616.         rectf(-x, -y, 2.0*x, 2.0*y);
  617.  
  618.       if (ship == targ) {            // highlight if current target
  619.         cpack(0xffffffff);
  620.         rect(-4.0*x, -4.0*y, 4.0*x, 4.0*y);
  621.       }
  622.  
  623.       if (ship->flag() != NoTeam) {        // draw flag if it has one
  624.         cpack(teamColor(ship->flag()));
  625.         rectf(0.0, -3.0*y, 0.0, 3.0*y);
  626.         rectf(-3.0*x, 0.0, 3.0*x, 0.0);
  627.       }
  628.         popmatrix();
  629.       }
  630.  
  631.       cpack(0xffffffff);
  632.       for (int j = 0; j < MAXMISSILES; j++) {
  633.     if (info.missile[j].active == ObjectActive) {
  634.       pushmatrix();
  635.         translate(playerView[i][j+1].lp[0], -playerView[i][j+1].lp[2],
  636.                         playerView[i][j+1].lp[1]);
  637.         if (playerView[i][j+1].lp[1] < 0.0)
  638.           rectf(0.0, 0.0, 0.5*x, 0.5*y);
  639.         else
  640.           rectf(0.0, 0.0, 1.5*x, 0.5*y);
  641.       popmatrix();
  642.     }
  643.       }
  644.     }
  645.  
  646.     // draw circles for bases
  647.     SbVec3f p;
  648.     for (i = 0; i < NUMTEAMS; i++) {
  649.       cpack(teamColor(Team(i)));
  650.       myShip->findLocalPosition(basePosition(Team(i)), p);
  651.       pushmatrix();
  652.     translate(p[0], -p[2], p[1]);
  653.     drawRadarBase(Team(i));
  654.       popmatrix();
  655.     }
  656.  
  657.     // draw asteroids
  658.     cpack(0xff808080);
  659.     for (i = 0; i < numberAsteroids(); i++) {
  660.       pushmatrix();
  661.     translate(asteroidView[i].lp[0], -asteroidView[i].lp[2],
  662.                         asteroidView[i].lp[1]);
  663.     drawRadarAsteroid(i);
  664.       popmatrix();
  665.     }
  666.  
  667.     // draw flags not on ships
  668.     for (i = 0; i < NUMTEAMS; i++) {
  669.       if (getTeam(Team(i)).state == FlagReady) {
  670.     cpack(teamColor(Team(i)));
  671.     pushmatrix();
  672.       translate(flagView[i].lp[0], -flagView[i].lp[2], flagView[i].lp[1]);
  673.       rectf(0.0, -3.0*y, 0.0, 3.0*y);
  674.       rectf(-3.0*x, 0.0, 3.0*x, 0.0);
  675.     popmatrix();
  676.       }
  677.     }
  678.  
  679.   popmatrix();
  680.  
  681.   // draw dot for me
  682.   cpack(0xff4080c0);
  683.   sboxf(-2.0*s->x, -2.0*s->y, 2.0*s->x, 2.0*s->y);
  684.   if (myShip->flag() != NoTeam) {
  685.     cpack(teamColor(myShip->flag()));
  686.     sboxf(0.0, -3.0*s->y, 0.0, 3.0*s->y);
  687.     sboxf(-3.0*s->x, 0.0, 3.0*s->x, 0.0);
  688.   }
  689.  
  690.   // draw range
  691.   font(0);
  692.   cpack(0xffdddddd);
  693.   cmov2(-1.0 + 4.0 * s->x, -1.0 + s->y * (4.0 + float(getdescender())));
  694.   char buf[20];
  695.   sprintf(buf, "%d", int(radarRange() / 1000.0));
  696.   charstr(buf);
  697.  
  698.   swapbuffers();
  699. }
  700.  
  701. static void        resizeRadar(GlxSize* s)
  702. {
  703.   s->x = 2.0 / float(s->dx);
  704.   s->y = 2.0 / float(s->dy);
  705. }
  706.  
  707. //
  708. // Target callbacks
  709. //
  710.  
  711. static void        targetNumChanged(Widget, caddr_t u,
  712.                     XmArrowButtonCallbackStruct* b)
  713. {
  714.   if (b->reason == XmCR_ACTIVATE) {
  715.     switch (int(u)) {
  716.       case 0: prevTarget(); break;
  717.       case 1: nextTarget(); break;
  718.     }
  719.   }
  720. }
  721.  
  722. static void        drawTarget(GlxSize* s, int forced)
  723. {
  724.   int changed = FALSE, td, th, tp, tNum = currentTarget();
  725.  
  726.   // get target info
  727.   ShipObject* tObj = (tNum == -1) ? NULL : getTarget(tNum);
  728.   if (tObj) {
  729.     SbVec3f tPos = tObj->position();
  730.     tPos -= myShip->position();
  731.     float dist = tPos.length();
  732.     th = int(atan2(tPos[2], tPos[0]) * 180.0 / M_PI + 0.5);
  733.     if (th < 0) th += 360;
  734.     tp = int(asin(tPos[1] / dist) * 180.0 / M_PI + 0.5);
  735.     td = int(dist / 100.0 + 0.5);
  736.     if (!forced &&                // if not a forced redraw
  737.     oldTarget == tObj &&            // and same target object
  738.     th == oldTargetHeading &&        // and same heading
  739.     tp == oldTargetPitch &&            // and same pitch
  740.     td == oldTargetDist)            // and same distance
  741.     return;                    // then no difference
  742.   }
  743.   else if (!forced && !oldTarget) return;    // if still no target, return
  744.   oldTarget = tObj;
  745.  
  746.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  747.   cpack(0xff000000);                // clear display
  748.   clear();
  749.   if (tNum == -1) return;            // no target
  750.  
  751.   oldTargetHeading = th;
  752.   oldTargetPitch = tp;
  753.   oldTargetDist = td;
  754.  
  755.   // draw name, team and class
  756.   font(0);
  757.   short d = short(getdescender()), h = short(getheight()),
  758.     y = short(s->dy) - h + d - 2;
  759.   cpack(0xffc0c0c0);
  760.   cmov2s(2, y);
  761.   charstr(tObj->name());
  762.   cpack(teamColor(tObj->team()) | 0xff7f7f7f);
  763.   cmov2s(2, y -= h);
  764.   charstr(teamName(tObj->team()));
  765.   cpack(0xffc0c0c0);
  766.   cmov2s(2, y -= h);
  767.   charstr(shipClassName(tObj->shipClass()));
  768.  
  769.   // draw heading/pitch to target
  770.   char buf[30];
  771.   sprintf(buf, "%d/%d", th, tp);
  772.   cmov2s(2, y -= h + 4);
  773.   charstr(buf);
  774.  
  775.   // draw range to target
  776.   sprintf(buf, "%d.%d km", td / 10, td % 10);
  777.   cmov2s(2, y -= h);
  778.   charstr(buf);
  779. }
  780.  
  781. //
  782. // Team color box callback
  783. //
  784.  
  785. static void        drawTeamColor(GlxSize* s, int)
  786. {
  787.   GLXwinset(XtDisplay(s->w), XtWindow(s->w));
  788.   cpack(teamColor(myShip->team()));
  789.   clear();
  790. }
  791.  
  792. //
  793. // General button callbacks
  794. //
  795.  
  796. static void        pauseCallback(Widget, caddr_t, caddr_t)
  797. {
  798.   togglePauseGame();
  799. }
  800.  
  801. static void        helpCallback(Widget, caddr_t, caddr_t)
  802. {
  803.   showHelp();
  804. }
  805.  
  806. static void        quitCallback(Widget, caddr_t, caddr_t)
  807. {
  808.   quitGame();
  809. }
  810.  
  811. //
  812. // End control panel callback functions
  813. //
  814.  
  815. //
  816. // Begin control panel creation routines
  817. //
  818.  
  819. static Widget        makeLabel(Widget parent)
  820. {
  821.   Widget w = XmCreateLabelGadget(parent, "label", NULL, 0);
  822.   XtManageChild(w);
  823.   return w;
  824. }
  825.  
  826. static Widget        makeInfo(Widget parent)
  827. {
  828.   Widget w = XmCreateLabelGadget(parent, "info", NULL, 0);
  829.   XtManageChild(w);
  830.   XmString s = XmStringCreateSimple("");
  831.   XtVaSetValues(w, XmNlabelString, s, NULL);
  832.   XmStringFree(s);
  833.   return w;
  834. }
  835.  
  836. static Widget        makeButton(Widget parent, char* name,
  837.                 int userData = 0, XtCallbackProc cb = NULL)
  838. {
  839.   Widget w = XmCreatePushButtonGadget(parent, name, NULL, 0);
  840.   XtManageChild(w);
  841.   if (cb)
  842.     XtAddCallback(w, XmNactivateCallback, cb, (XtPointer)userData);
  843.   return w;
  844. }
  845.  
  846. static Widget        makeRadio(Widget parent, char* name,
  847.                 int userData = 0, XtCallbackProc cb = NULL)
  848. {
  849.   Widget w = XmCreateToggleButtonGadget(parent, name, NULL, 0);
  850.   XtManageChild(w);
  851.   XtVaSetValues(w,
  852.     XmNuserData,        (void*)userData,
  853.     NULL);
  854.   if (cb)
  855.     XtAddCallback(w, XmNvalueChangedCallback, cb, (XtPointer)userData);
  856.   return w;
  857. }
  858.  
  859. static Widget        makeArrow(Widget parent, char* name, unsigned char d,
  860.                 int userData = 0, XtCallbackProc cb = NULL)
  861. {
  862.   Widget w = XmCreateArrowButtonGadget(parent, name, NULL, 0);
  863.   XtManageChild(w);
  864.   XtVaSetValues(w,
  865.     XmNarrowDirection,    d,
  866.     XmNshadowThickness,    0,
  867.     NULL);
  868.   if (cb)
  869.     XtAddCallback(w, XmNactivateCallback, cb, (XtPointer)userData);
  870.   return w;
  871. }
  872.  
  873. static Widget        makeBox(Widget parent)
  874. {
  875.   Widget w = XmCreateFrame(parent, "", NULL, 0);
  876.   XtManageChild(w);
  877.   XtVaSetValues(w,
  878.     XmNshadowType,        XmSHADOW_ETCHED_IN,
  879.     XmNmarginWidth,        0,
  880.     XmNmarginHeight,    0,
  881.     NULL);
  882.   return w;
  883. }
  884.  
  885. static GLXconfig    glxConfig[] =
  886.                 { {GLX_NORMAL, GLX_DOUBLE, FALSE},
  887.                   {GLX_NORMAL, GLX_RGB, TRUE},
  888.                   {0, 0, 0} };
  889. static GLXconfig    glxRConfig[] =
  890.                 { {GLX_NORMAL, GLX_DOUBLE, TRUE},
  891.                   {GLX_NORMAL, GLX_RGB, TRUE},
  892.                   {GLX_NORMAL, GLX_ZSIZE, GLX_NOCONFIG},
  893.                   {0, 0, 0} };
  894.  
  895. static Widget        makeDrawArea(Widget parent, char* name, int dx, int dy)
  896. {
  897.   Arg args[1];
  898.   GLXconfig* c = GLXgetconfig(XtDisplay(parent),
  899.             XScreenNumberOfScreen(XtScreen(parent)), glxConfig);
  900.   XtSetArg(args[0], GlxNglxConfig, c);
  901.   Widget w = GlxCreateMDraw(parent, name, args, 1);
  902.   XtManageChild(w);
  903.   free(c);
  904.   XtVaSetValues(w,
  905.     XmNwidth,        dx,
  906.     XmNheight,        dy,
  907.     NULL);
  908.   return w;
  909. }
  910.  
  911. static Widget        makeUnitDrawArea(Widget parent, char* name,
  912.                                 GlxSize* size)
  913. {
  914.   Widget w = makeDrawArea(parent, name, size->dx, size->dy);
  915.   XtAddCallback(w, GlxNginitCallback, (XtCallbackProc)unitInitCallback, (XtPointer)size);
  916.   XtAddCallback(w, GlxNresizeCallback, (XtCallbackProc)unitResizeCallback, (XtPointer)size);
  917.   XtAddCallback(w, GlxNexposeCallback, (XtCallbackProc)glxDrawCallback, (XtPointer)size);
  918.   if (size) size->w = w;
  919.   return w;
  920. }
  921.  
  922. static Widget        makePixelDrawArea(Widget parent, char* name,
  923.                                 GlxSize* size)
  924. {
  925.   Widget w = makeDrawArea(parent, name, size->dx, size->dy);
  926.   XtAddCallback(w, GlxNginitCallback, (XtCallbackProc)pixelInitCallback, (XtPointer)size);
  927.   XtAddCallback(w, GlxNresizeCallback, (XtCallbackProc)pixelResizeCallback, (XtPointer)size);
  928.   XtAddCallback(w, GlxNexposeCallback, (XtCallbackProc)glxDrawCallback, (XtPointer)size);
  929.   if (size) size->w = w;
  930.   return w;
  931. }
  932.  
  933. static Widget        makeRadarDrawArea(Widget parent, char* name,
  934.                                 GlxSize* size)
  935. {
  936.   Arg args[1];
  937.   GLXconfig* c = GLXgetconfig(XtDisplay(parent),
  938.             XScreenNumberOfScreen(XtScreen(parent)), glxRConfig);
  939.   XtSetArg(args[0], GlxNglxConfig, c);
  940.   Widget w = GlxCreateMDraw(parent, name, args, 1);
  941.   XtManageChild(w);
  942.   free(c);
  943.   XtVaSetValues(w,
  944.     XmNwidth,        size->dx,
  945.     XmNheight,        size->dy,
  946.     NULL);
  947.   XtAddCallback(w, GlxNginitCallback, (XtCallbackProc)radarInitCallback, (XtPointer)size);
  948.   XtAddCallback(w, GlxNresizeCallback, (XtCallbackProc)radarResizeCallback, (XtPointer)size);
  949.   XtAddCallback(w, GlxNexposeCallback, (XtCallbackProc)glxDrawCallback, (XtPointer)size);
  950.   if (size) size->w = w;
  951.   return w;
  952. }
  953.  
  954. static Widget        makeShipStatus(Widget top)
  955. {
  956.   // make ship status form (weapon, shield, fuel, and thrust status)
  957.   Widget statusForm = XmCreateForm(top, "status", NULL, 0);
  958.   XtManageChild(statusForm);
  959.  
  960.   // make weapon select and shield readouts
  961.   Widget weaponForm = XmCreateForm(statusForm, "weapons", NULL, 0);
  962.   XtManageChild(weaponForm);
  963.   Widget weaponLabel = makeLabel(weaponForm);
  964.   Widget weaponBox = makeBox(weaponForm);
  965.   Widget shieldForm = XmCreateForm(statusForm, "shields", NULL, 0);
  966.   XtManageChild(shieldForm);
  967.   Widget shieldLabel = makeLabel(shieldForm);
  968.   Widget shieldBox = makeBox(shieldForm);
  969.   XtVaSetValues(weaponForm,
  970.     XmNtopAttachment,    XmATTACH_FORM,
  971.     XmNleftAttachment,    XmATTACH_FORM,
  972.     NULL);
  973.   XtVaSetValues(weaponLabel,
  974.     XmNtopAttachment,    XmATTACH_FORM,
  975.     XmNleftAttachment,    XmATTACH_FORM,
  976.     NULL);
  977.   XtVaSetValues(weaponBox,
  978.     XmNtopAttachment,    XmATTACH_WIDGET,
  979.     XmNbottomAttachment,    XmATTACH_FORM,
  980.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  981.     XmNrightAttachment,    XmATTACH_FORM,
  982.     XmNtopWidget,        weaponLabel,
  983.     XmNleftWidget,        weaponLabel,
  984.     NULL);
  985.   XtVaSetValues(shieldForm,
  986.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  987.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  988.     XmNleftAttachment,    XmATTACH_WIDGET,
  989.     XmNtopWidget,        weaponForm,
  990.     XmNbottomWidget,    weaponForm,
  991.     XmNleftWidget,        weaponForm,
  992.     XmNleftOffset,        8,
  993.     NULL);
  994.   XtVaSetValues(shieldLabel,
  995.     XmNtopAttachment,    XmATTACH_FORM,
  996.     XmNleftAttachment,    XmATTACH_FORM,
  997.     NULL);
  998.   XtVaSetValues(shieldBox,
  999.     XmNtopAttachment,    XmATTACH_WIDGET,
  1000.     XmNbottomAttachment,    XmATTACH_FORM,
  1001.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1002.     XmNrightAttachment,    XmATTACH_FORM,
  1003.     XmNtopWidget,        shieldLabel,
  1004.     XmNleftWidget,        shieldLabel,
  1005.     NULL);
  1006.   XtAddCallback(makeUnitDrawArea(weaponBox, "info", &weaponSize),
  1007.         GlxNinputCallback, (XtCallbackProc)inputWeapon, (XtPointer)&weaponSize);
  1008.   makePixelDrawArea(shieldBox, "info", &shieldSize);
  1009.  
  1010.   // make laser temp., missile count, thrust level, and fuel level readouts
  1011.   Widget laserForm = XmCreateForm(statusForm, "laser", NULL, 0);
  1012.   XtManageChild(laserForm);
  1013.   Widget laserLabel = makeLabel(laserForm);
  1014.   Widget laserBox = makeBox(laserForm);
  1015.   Widget missileForm = XmCreateForm(statusForm, "missile", NULL, 0);
  1016.   XtManageChild(missileForm);
  1017.   Widget missileLabel = makeLabel(missileForm);
  1018.   Widget missileBox = makeBox(missileForm);
  1019.   Widget thrustForm = XmCreateForm(statusForm, "thrust", NULL, 0);
  1020.   XtManageChild(thrustForm);
  1021.   Widget thrustLabel = makeLabel(thrustForm);
  1022.   Widget thrustBox = makeBox(thrustForm);
  1023.   Widget fuelForm = XmCreateForm(statusForm, "fuel", NULL, 0);
  1024.   XtManageChild(fuelForm);
  1025.   Widget fuelLabel = makeLabel(fuelForm);
  1026.   Widget fuelBox = makeBox(fuelForm);
  1027.  
  1028.   XtVaSetValues(laserForm,
  1029.     XmNtopAttachment,    XmATTACH_WIDGET,
  1030.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1031.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1032.     XmNtopWidget,        weaponForm,
  1033.     XmNleftWidget,        weaponForm,
  1034.     XmNrightWidget,        shieldForm,
  1035.     XmNtopOffset,        6,
  1036.     NULL);
  1037.   XtVaSetValues(laserLabel,
  1038.     XmNtopAttachment,    XmATTACH_FORM,
  1039.     XmNrightAttachment,    XmATTACH_POSITION,
  1040.     NULL);
  1041.   XtVaSetValues(laserBox,
  1042.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1043.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1044.     XmNleftAttachment,    XmATTACH_WIDGET,
  1045.     XmNrightAttachment,    XmATTACH_FORM,
  1046.     XmNtopWidget,        laserLabel,
  1047.     XmNbottomWidget,    laserLabel,
  1048.     XmNleftWidget,        laserLabel,
  1049.     XmNleftOffset,        8,
  1050.     NULL);
  1051.   XtVaSetValues(missileForm,
  1052.     XmNtopAttachment,    XmATTACH_WIDGET,
  1053.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1054.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1055.     XmNtopWidget,        laserForm,
  1056.     XmNleftWidget,        laserForm,
  1057.     XmNrightWidget,        laserForm,
  1058.     XmNtopOffset,        6,
  1059.     NULL);
  1060.   XtVaSetValues(missileLabel,
  1061.     XmNtopAttachment,    XmATTACH_FORM,
  1062.     XmNrightAttachment,    XmATTACH_POSITION,
  1063.     NULL);
  1064.   XtVaSetValues(missileBox,
  1065.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1066.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1067.     XmNleftAttachment,    XmATTACH_WIDGET,
  1068.     XmNrightAttachment,    XmATTACH_FORM,
  1069.     XmNtopWidget,        missileLabel,
  1070.     XmNbottomWidget,    missileLabel,
  1071.     XmNleftWidget,        missileLabel,
  1072.     XmNleftOffset,        8,
  1073.     NULL);
  1074.   XtVaSetValues(thrustForm,
  1075.     XmNtopAttachment,    XmATTACH_WIDGET,
  1076.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1077.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1078.     XmNtopWidget,        missileForm,
  1079.     XmNleftWidget,        missileForm,
  1080.     XmNrightWidget,        missileForm,
  1081.     XmNtopOffset,        6,
  1082.     NULL);
  1083.   XtVaSetValues(thrustLabel,
  1084.     XmNtopAttachment,    XmATTACH_FORM,
  1085.     XmNrightAttachment,    XmATTACH_POSITION,
  1086.     NULL);
  1087.   XtVaSetValues(thrustBox,
  1088.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1089.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1090.     XmNleftAttachment,    XmATTACH_WIDGET,
  1091.     XmNrightAttachment,    XmATTACH_FORM,
  1092.     XmNtopWidget,        thrustLabel,
  1093.     XmNbottomWidget,    thrustLabel,
  1094.     XmNleftWidget,        thrustLabel,
  1095.     XmNleftOffset,        8,
  1096.     NULL);
  1097.   XtVaSetValues(fuelForm,
  1098.     XmNtopAttachment,    XmATTACH_WIDGET,
  1099.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1100.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1101.     XmNtopWidget,        thrustForm,
  1102.     XmNleftWidget,        thrustForm,
  1103.     XmNrightWidget,        thrustForm,
  1104.     XmNtopOffset,        6,
  1105.     NULL);
  1106.   XtVaSetValues(fuelLabel,
  1107.     XmNtopAttachment,    XmATTACH_FORM,
  1108.     XmNrightAttachment,    XmATTACH_POSITION,
  1109.     NULL);
  1110.   XtVaSetValues(fuelBox,
  1111.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1112.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1113.     XmNleftAttachment,    XmATTACH_WIDGET,
  1114.     XmNrightAttachment,    XmATTACH_FORM,
  1115.     XmNtopWidget,        fuelLabel,
  1116.     XmNbottomWidget,    fuelLabel,
  1117.     XmNleftWidget,        fuelLabel,
  1118.     XmNleftOffset,        8,
  1119.     NULL);
  1120.  
  1121.   makePixelDrawArea(laserBox, "info", &laserSize);
  1122.   makePixelDrawArea(missileBox, "info", &missileSize);
  1123.   makePixelDrawArea(thrustBox, "info", &thrustSize);
  1124.   makePixelDrawArea(fuelBox, "info", &fuelSize);
  1125.  
  1126.   return statusForm;
  1127. }
  1128.  
  1129. static Widget        makeRadioControls(Widget top)
  1130. {
  1131.   // make radio controls
  1132.   Widget radioForm = XmCreateForm(top, "radio", NULL, 0);
  1133.   XtManageChild(radioForm);
  1134.   Widget radioLabel = makeLabel(radioForm);
  1135.   Widget radioRadio = XmCreateRadioBox(radioForm, "", NULL, 0);
  1136.   XtManageChild(radioRadio);
  1137.   radioToggle[0] = makeRadio(radioRadio, "off", RadioOff,
  1138.                     (XtCallbackProc)radioChanged);
  1139.   radioToggle[1] = makeRadio(radioRadio, "team", RadioTeam,
  1140.                     (XtCallbackProc)radioChanged);
  1141.   radioToggle[2] = makeRadio(radioRadio, "all", RadioAll,
  1142.                     (XtCallbackProc)radioChanged);
  1143.   XtVaSetValues(radioLabel,
  1144.     XmNtopAttachment,    XmATTACH_FORM,
  1145.     XmNleftAttachment,    XmATTACH_FORM,
  1146.     NULL);
  1147.   XtVaSetValues(radioRadio,
  1148.     XmNtopAttachment,    XmATTACH_WIDGET,
  1149.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1150.     XmNtopWidget,        radioLabel,
  1151.     XmNleftWidget,        radioLabel,
  1152.     NULL);
  1153.  
  1154.   // initialize toggle buttons
  1155.   XmToggleButtonGadgetSetState(radioToggle[0], TRUE, TRUE);
  1156.  
  1157.   return radioForm;
  1158. }
  1159.  
  1160. static Widget        makeSoundControls(Widget top)
  1161. {
  1162.   // make sound controls
  1163.   Widget soundForm = XmCreateForm(top, "sound", NULL, 0);
  1164.   XtManageChild(soundForm);
  1165.   Widget soundLabel = makeLabel(soundForm);
  1166.   Widget soundRadio = XmCreateRadioBox(soundForm, "", NULL, 0);
  1167.   XtManageChild(soundRadio);
  1168.   soundToggle[0] = makeRadio(soundRadio, "off", SoundOff,
  1169.                     (XtCallbackProc)soundChanged);
  1170.   soundToggle[1] = makeRadio(soundRadio, "warning", SoundWarnings,
  1171.                     (XtCallbackProc)soundChanged);
  1172.   soundToggle[2] = makeRadio(soundRadio, "all", SoundAll,
  1173.                     (XtCallbackProc)soundChanged);
  1174.   XtVaSetValues(soundLabel,
  1175.     XmNtopAttachment,    XmATTACH_FORM,
  1176.     XmNleftAttachment,    XmATTACH_FORM,
  1177.     NULL);
  1178.   XtVaSetValues(soundRadio,
  1179.     XmNtopAttachment,    XmATTACH_WIDGET,
  1180.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1181.     XmNtopWidget,        soundLabel,
  1182.     XmNleftWidget,        soundLabel,
  1183.     NULL);
  1184.  
  1185.   // initialize toggle buttons
  1186.   XmToggleButtonGadgetSetState(soundToggle[0], TRUE, TRUE);
  1187.  
  1188.   return soundForm;
  1189. }
  1190.  
  1191. static Widget        makeRadar(Widget top)
  1192. {
  1193.   // make radar form
  1194.   Widget radar = XmCreateForm(top, "radar", NULL, 0);
  1195.   XtManageChild(radar);
  1196.  
  1197.   // make radar controls
  1198.   Widget radarLabel = makeLabel(radar);
  1199.   Widget radarUp = makeArrow(radar, "down", XmARROW_DOWN, 0,
  1200.                     (XtCallbackProc)radarRangeChanged);
  1201.   Widget radarDown = makeArrow(radar, "up", XmARROW_UP, 1,
  1202.                     (XtCallbackProc)radarRangeChanged);
  1203.   Widget radarBox = makeBox(radar);
  1204.   XtVaSetValues(radarLabel,
  1205.     XmNtopAttachment,    XmATTACH_FORM,
  1206.     XmNleftAttachment,    XmATTACH_FORM,
  1207.     NULL);
  1208.   XtVaSetValues(radarUp,
  1209.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1210.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1211.     XmNrightAttachment,    XmATTACH_WIDGET,
  1212.     XmNtopWidget,        radarLabel,
  1213.     XmNbottomWidget,    radarLabel,
  1214.     XmNrightWidget,        radarDown,
  1215.     NULL);
  1216.   XtVaSetValues(radarDown,
  1217.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1218.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1219.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1220.     XmNtopWidget,        radarLabel,
  1221.     XmNbottomWidget,    radarLabel,
  1222.     XmNrightWidget,        radarBox,
  1223.     NULL);
  1224.   XtVaSetValues(radarBox,
  1225.     XmNtopAttachment,    XmATTACH_WIDGET,
  1226.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1227.     XmNtopWidget,        radarLabel,
  1228.     XmNleftWidget,        radarLabel,
  1229.     NULL);
  1230.   makeRadarDrawArea(radarBox, "info", &radarSize);
  1231.  
  1232.   return radar;
  1233. }
  1234.  
  1235. static Widget        makeTargetStatus(Widget top)
  1236. {
  1237.   // make target form
  1238.   Widget targetStatus = XmCreateForm(top, "target", NULL, 0);
  1239.   XtManageChild(targetStatus);
  1240.  
  1241.   // make target controls
  1242.   Widget targetLabel = makeLabel(targetStatus);
  1243.   Widget targetPrev = makeArrow(targetStatus, "prev", XmARROW_LEFT, 0,
  1244.                     (XtCallbackProc)targetNumChanged);
  1245.   Widget targetNext = makeArrow(targetStatus, "next", XmARROW_RIGHT, 1,
  1246.                     (XtCallbackProc)targetNumChanged);
  1247.   Widget targetBox = makeBox(targetStatus);
  1248.   XtVaSetValues(targetLabel,
  1249.     XmNtopAttachment,    XmATTACH_FORM,
  1250.     XmNleftAttachment,    XmATTACH_FORM,
  1251.     NULL);
  1252.   XtVaSetValues(targetPrev,
  1253.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1254.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1255.     XmNrightAttachment,    XmATTACH_WIDGET,
  1256.     XmNtopWidget,        targetLabel,
  1257.     XmNbottomWidget,    targetLabel,
  1258.     XmNrightWidget,        targetNext,
  1259.     NULL);
  1260.   XtVaSetValues(targetNext,
  1261.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1262.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1263.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1264.     XmNtopWidget,        targetLabel,
  1265.     XmNbottomWidget,    targetLabel,
  1266.     XmNrightWidget,        targetBox,
  1267.     NULL);
  1268.   XtVaSetValues(targetBox,
  1269.     XmNtopAttachment,    XmATTACH_WIDGET,
  1270.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1271.     XmNtopWidget,        targetLabel,
  1272.     XmNleftWidget,        targetLabel,
  1273.     NULL);
  1274.   makePixelDrawArea(targetBox, "info", &targetSize);
  1275.  
  1276.   return targetStatus;
  1277. }
  1278.  
  1279. static Widget        makeGeneralInfo(Widget top)
  1280. {
  1281.   // make general info layout
  1282.   Widget info = XmCreateForm(top, "", NULL, 0);
  1283.   XtManageChild(info);
  1284.  
  1285.   // make general info readouts
  1286.   Widget score = XmCreateForm(info, "score", NULL, 0);
  1287.   XtManageChild(score);
  1288.   Widget scoreLabel = makeLabel(score);
  1289.   scoreInfo = makeInfo(score);
  1290.   Widget players = XmCreateForm(info, "players", NULL, 0);
  1291.   XtManageChild(players);
  1292.   Widget playersLabel = makeLabel(players);
  1293.   playersInfo = makeInfo(players);
  1294.   Widget flag = XmCreateForm(info, "flag", NULL, 0);
  1295.   XtManageChild(flag);
  1296.   Widget flagLabel = makeLabel(flag);
  1297.   flagInfo = makeInfo(flag);
  1298.   XtVaSetValues(score,
  1299.     XmNtopAttachment,    XmATTACH_FORM,
  1300.     XmNleftAttachment,    XmATTACH_FORM,
  1301.     XmNrightAttachment,    XmATTACH_FORM,
  1302.     NULL);
  1303.   XtVaSetValues(scoreLabel,
  1304.     XmNtopAttachment,    XmATTACH_FORM,
  1305.     XmNleftAttachment,    XmATTACH_FORM,
  1306.     NULL);
  1307.   XtVaSetValues(scoreInfo,
  1308.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1309.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1310.     XmNleftAttachment,    XmATTACH_WIDGET,
  1311.     XmNtopWidget,        scoreLabel,
  1312.     XmNbottomWidget,    scoreLabel,
  1313.     XmNleftWidget,        scoreLabel,
  1314.     XmNleftOffset,        8,
  1315.     NULL);
  1316.   XtVaSetValues(players,
  1317.     XmNtopAttachment,    XmATTACH_WIDGET,
  1318.     XmNleftAttachment,    XmATTACH_FORM,
  1319.     XmNrightAttachment,    XmATTACH_FORM,
  1320.     XmNtopWidget,        score,
  1321.     NULL);
  1322.   XtVaSetValues(playersLabel,
  1323.     XmNtopAttachment,    XmATTACH_FORM,
  1324.     XmNleftAttachment,    XmATTACH_FORM,
  1325.     NULL);
  1326.   XtVaSetValues(playersInfo,
  1327.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1328.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1329.     XmNleftAttachment,    XmATTACH_WIDGET,
  1330.     XmNtopWidget,        playersLabel,
  1331.     XmNbottomWidget,    playersLabel,
  1332.     XmNleftWidget,        playersLabel,
  1333.     XmNleftOffset,        8,
  1334.     NULL);
  1335.   XtVaSetValues(flag,
  1336.     XmNtopAttachment,    XmATTACH_WIDGET,
  1337.     XmNbottomAttachment,    XmATTACH_FORM,
  1338.     XmNleftAttachment,    XmATTACH_FORM,
  1339.     XmNrightAttachment,    XmATTACH_FORM,
  1340.     XmNtopWidget,        players,
  1341.     NULL);
  1342.   XtVaSetValues(flagLabel,
  1343.     XmNtopAttachment,    XmATTACH_FORM,
  1344.     XmNleftAttachment,    XmATTACH_FORM,
  1345.     NULL);
  1346.   XtVaSetValues(flagInfo,
  1347.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1348.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1349.     XmNleftAttachment,    XmATTACH_WIDGET,
  1350.     XmNtopWidget,        flagLabel,
  1351.     XmNbottomWidget,    flagLabel,
  1352.     XmNleftWidget,        flagLabel,
  1353.     XmNleftOffset,        8,
  1354.     NULL);
  1355.  
  1356.   return info;
  1357. }
  1358.  
  1359. static Widget        makeMessages(Widget top)
  1360. {
  1361.   // make messges form
  1362.   Widget messages = XmCreateForm(top, "message", NULL, 0);
  1363.   XtManageChild(messages);
  1364.  
  1365.   // make messges stuff
  1366.   if (msgBuffer) free(msgBuffer);
  1367.   Widget msgLabel = makeLabel(messages);
  1368.   Arg args[5];
  1369.   XtSetArg(args[0], XmNeditable,        FALSE);
  1370.   XtSetArg(args[1], XmNeditMode,        XmMULTI_LINE_EDIT);
  1371.   XtSetArg(args[2], XmNwordWrap,        FALSE);
  1372.   XtSetArg(args[3], XmNcursorPositionVisible,    FALSE);
  1373.   XtSetArg(args[4], XmNhighlightThickness,    0);
  1374.   msgText = XmCreateScrolledText(messages, "info", args, 5);
  1375.   XtManageChild(msgText);
  1376.   msgBuffer = (char*) malloc(sizeof(char) * 81 * MAXMESSAGES);
  1377.   memset(msgBuffer, ' ', 81 * MAXMESSAGES);
  1378.   for (int i = 0; i < MAXMESSAGES-1; i++)
  1379.     msgBuffer[i * 81 + 80] = '\n';
  1380.   msgBuffer[i * 81 + 80] = 0;
  1381.   XmTextSetString(msgText, msgBuffer);
  1382.   XmTextShowPosition(msgText, 81 * (MAXMESSAGES-1));
  1383.  
  1384.   XtVaSetValues(msgLabel,
  1385.     XmNtopAttachment,    XmATTACH_FORM,
  1386.     XmNleftAttachment,    XmATTACH_FORM,
  1387.     NULL);
  1388.   XtVaSetValues(XtParent(msgText),
  1389.     XmNtopAttachment,    XmATTACH_WIDGET,
  1390.     XmNbottomAttachment,    XmATTACH_FORM,
  1391.     XmNleftAttachment,    XmATTACH_FORM,
  1392.     XmNrightAttachment,    XmATTACH_FORM,
  1393.     XmNtopWidget,        msgLabel,
  1394.     XmNscrollBarPlacement,    XmBOTTOM_RIGHT,
  1395.     XmNheight,        144,
  1396.     NULL);
  1397.  
  1398.   // no highlight around scrollbars
  1399.   Widget sb;
  1400.   XtVaGetValues(XtParent(msgText), XmNhorizontalScrollBar, &sb, NULL);
  1401.   if (sb) {
  1402.     XtVaSetValues(sb,
  1403.     XmNhighlightThickness,    0,
  1404.     XmNheight,        18,
  1405.     NULL);
  1406.   }
  1407.   XtVaGetValues(XtParent(msgText), XmNverticalScrollBar, &sb, NULL);
  1408.   if (sb) {
  1409.     XtVaSetValues(sb,
  1410.     XmNhighlightThickness,    0,
  1411.     XmNwidth,        18,
  1412.     NULL);
  1413.   }
  1414.  
  1415.   return messages;
  1416. }
  1417.  
  1418. static Widget        makeGeneralButtons(Widget top)
  1419. {
  1420.   // make general button layout
  1421.   Widget general = XmCreateForm(top, "", NULL, 0);
  1422.   XtManageChild(general);
  1423.  
  1424.   // make general buttons
  1425.   Widget pauseButton = makeButton(general, "pause", 0, (XtCallbackProc)pauseCallback);
  1426.   Widget helpButton = makeButton(general, "help", 0, (XtCallbackProc)helpCallback);
  1427.   Widget quitButton = makeButton(general, "quit", 0, (XtCallbackProc)quitCallback);
  1428.   XtVaSetValues(pauseButton,
  1429.     XmNtopAttachment,    XmATTACH_FORM,
  1430.     XmNrightAttachment,    XmATTACH_FORM,
  1431.     XmNwidth,        75,
  1432.     NULL);
  1433.   XtVaSetValues(quitButton,
  1434.     XmNtopAttachment,    XmATTACH_WIDGET,
  1435.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1436.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1437.     XmNtopWidget,        pauseButton,
  1438.     XmNleftWidget,        pauseButton,
  1439.     XmNrightWidget,        pauseButton,
  1440.     XmNtopOffset,        6,
  1441.     NULL);
  1442.   XtVaSetValues(helpButton,
  1443.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1444.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1445.     XmNrightAttachment,    XmATTACH_WIDGET,
  1446.     XmNtopWidget,        quitButton,
  1447.     XmNbottomWidget,    quitButton,
  1448.     XmNrightWidget,        quitButton,
  1449.     XmNrightOffset,        8,
  1450.     XmNwidth,        75,
  1451.     NULL);
  1452.  
  1453.   return general;
  1454. }
  1455.  
  1456. static Widget        makeTeamColor(Widget top)
  1457. {
  1458.   Widget colorBox = makeBox(top);
  1459.   makeUnitDrawArea(colorBox, "info", &colorSize);
  1460.   return colorBox;
  1461. }
  1462.  
  1463. //
  1464. // End control panel creation routines
  1465. //
  1466.  
  1467. //
  1468. // external control panel functions
  1469. //    (okay, so makeControlPanel() is still a panel creation routine phhtttt)
  1470. //
  1471.  
  1472. Widget            makeControlPanel(Widget toplevel)
  1473. {
  1474.   Widget controls = XmCreateForm(toplevel, "controls", NULL, 0);
  1475.  
  1476.   Widget shipStatus = makeShipStatus(controls);
  1477.   XtVaSetValues(shipStatus,
  1478.     XmNtopAttachment,    XmATTACH_FORM,
  1479.     XmNbottomAttachment,    XmATTACH_FORM,
  1480.     XmNleftAttachment,    XmATTACH_FORM,
  1481.     XmNtopOffset,        4,
  1482.     XmNbottomOffset,    8,
  1483.     XmNleftOffset,        8,
  1484.     NULL);
  1485.  
  1486. #ifndef NORADIO
  1487.   Widget radioControls = makeRadioControls(controls);
  1488.   XtVaSetValues(radioControls,
  1489.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1490.     XmNleftAttachment,    XmATTACH_WIDGET,
  1491.     XmNtopWidget,        shipStatus,
  1492.     XmNleftWidget,        shipStatus,
  1493.     XmNleftOffset,        8,
  1494.     NULL);
  1495. #endif
  1496.  
  1497.   Widget soundControls = makeSoundControls(controls);
  1498.   XtVaSetValues(soundControls,
  1499. #ifndef NORADIO
  1500.     XmNtopAttachment,    XmATTACH_WIDGET,
  1501.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1502.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1503.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1504.     XmNtopWidget,        radioControls,
  1505.     XmNbottomWidget,    shipStatus,
  1506.     XmNleftWidget,        radioControls,
  1507.     XmNrightWidget,        radioControls,
  1508. #else
  1509.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1510.     XmNleftAttachment,    XmATTACH_WIDGET,
  1511.     XmNtopWidget,        shipStatus,
  1512.     XmNleftWidget,        shipStatus,
  1513.     XmNleftOffset,        8,
  1514. #endif
  1515.     NULL);
  1516.  
  1517.   Widget radar = makeRadar(controls);
  1518.   XtVaSetValues(radar,
  1519.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1520.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1521.     XmNleftAttachment,    XmATTACH_WIDGET,
  1522.     XmNtopWidget,        shipStatus,
  1523.     XmNbottomWidget,    shipStatus,
  1524. #ifndef NORADIO
  1525.     XmNleftWidget,        radioControls,
  1526. #else
  1527.     XmNleftWidget,        soundControls,
  1528. #endif
  1529.     XmNleftOffset,        8,
  1530.     NULL);
  1531.  
  1532.   Widget target = makeTargetStatus(controls);
  1533.   XtVaSetValues(target,
  1534.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1535.     XmNleftAttachment,    XmATTACH_WIDGET,
  1536.     XmNtopWidget,        shipStatus,
  1537.     XmNleftWidget,        radar,
  1538.     XmNleftOffset,        8,
  1539.     NULL);
  1540.  
  1541.   Widget info = makeGeneralInfo(controls);
  1542.   XtVaSetValues(info,
  1543.     XmNtopAttachment,    XmATTACH_WIDGET,
  1544.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1545.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1546.     XmNrightAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1547.     XmNtopWidget,        target,
  1548.     XmNbottomWidget,    shipStatus,
  1549.     XmNleftWidget,        target,
  1550.     XmNrightWidget,        target,
  1551.     XmNtopOffset,        8,
  1552.     NULL);
  1553.  
  1554.   Widget messages = makeMessages(controls);
  1555.   XtVaSetValues(messages,
  1556.     XmNtopAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1557.     XmNleftAttachment,    XmATTACH_WIDGET,
  1558.     XmNrightAttachment,    XmATTACH_FORM,
  1559.     XmNtopWidget,        target,
  1560.     XmNleftWidget,        target,
  1561.     XmNleftOffset,        8,
  1562.     XmNrightOffset,        8,
  1563.     NULL);
  1564.  
  1565.   Widget general = makeGeneralButtons(controls);
  1566.   XtVaSetValues(general,
  1567.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1568.     XmNrightAttachment,    XmATTACH_FORM,
  1569.     XmNbottomWidget,    shipStatus,
  1570.     XmNrightOffset,        8,
  1571.     NULL);
  1572.  
  1573.   Widget teamColor = makeTeamColor(controls);
  1574.   XtVaSetValues(teamColor,
  1575.     XmNtopAttachment,    XmATTACH_WIDGET,
  1576.     XmNbottomAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1577.     XmNleftAttachment,    XmATTACH_OPPOSITE_WIDGET,
  1578.     XmNtopWidget,        messages,
  1579.     XmNbottomWidget,    shipStatus,
  1580.     XmNleftWidget,        messages,
  1581.     XmNtopOffset,        6,
  1582.     NULL);
  1583.  
  1584.   return controls;
  1585. }
  1586.  
  1587. RadioSetting        radioDial()
  1588. {
  1589.   return radioState;
  1590. }
  1591.  
  1592. void            radioDial(RadioSetting r)
  1593. {
  1594.   if (radioState != r) {
  1595.     radioState = r;
  1596.     XmToggleButtonGadgetSetState(radioToggle[int(r)], TRUE, TRUE);
  1597.   }
  1598. }
  1599.  
  1600. SoundSetting        soundDial()
  1601. {
  1602.   return soundState;
  1603. }
  1604.  
  1605. void            soundDial(SoundSetting s)
  1606. {
  1607.   if (soundState != s) {
  1608.     soundState = s;
  1609.     XmToggleButtonGadgetSetState(soundToggle[int(s)], TRUE, TRUE);
  1610.   }
  1611. }
  1612.  
  1613. void            weaponChanged()
  1614. {
  1615.   drawWeapon(&weaponSize, FALSE);
  1616. }
  1617.  
  1618. void            laserChanged()
  1619. {
  1620.   drawLaser(&laserSize, FALSE);
  1621. }
  1622.  
  1623. void            missileChanged()
  1624. {
  1625.   drawMissile(&missileSize, FALSE);
  1626. }
  1627.  
  1628. void            thrustChanged()
  1629. {
  1630.   drawThrust(&thrustSize, FALSE);
  1631. }
  1632.  
  1633. void            fuelChanged()
  1634. {
  1635.   drawFuel(&fuelSize, FALSE);
  1636. }
  1637.  
  1638. void            shieldsChanged()
  1639. {
  1640.   drawShield(&shieldSize, FALSE);
  1641. }
  1642.  
  1643. void            targetChanged()
  1644. {
  1645.   drawTarget(&targetSize, FALSE);
  1646. }
  1647.  
  1648. void            scoreChanged()
  1649. {
  1650.   char buf[10];
  1651.   sprintf(buf, "%d", myShip->score());
  1652.   XmString s = XmStringCreateSimple(buf);
  1653.   XtVaSetValues(scoreInfo, XmNlabelString, s, NULL);
  1654.   XmStringFree(s);
  1655. }
  1656.  
  1657. void            playersChanged()
  1658. {
  1659.   char buf[10];
  1660.   sprintf(buf, "%d", numberPlayers());
  1661.   XmString s = XmStringCreateSimple(buf);
  1662.   XtVaSetValues(playersInfo, XmNlabelString, s, NULL);
  1663.   XmStringFree(s);
  1664. }
  1665.  
  1666. void            flagChanged()
  1667. {
  1668.   XmString s;
  1669.   if (myShip->flag() == NoTeam)
  1670.     s = XmStringCreateSimple("---");
  1671.   else
  1672.     s = XmStringCreateSimple(teamName(myShip->flag()));
  1673.   XtVaSetValues(flagInfo, XmNlabelString, s, NULL);
  1674.   XmStringFree(s);
  1675. }
  1676.  
  1677. void            addMessage(char* msg)
  1678. {
  1679.   // shift old messages up and add new message
  1680.   memmove(msgBuffer, msgBuffer + 81, 81 * (MAXMESSAGES-1) - 1);
  1681.   int l = strlen(msg);
  1682.   if (l > 80) l = 80;
  1683.   memcpy(msgBuffer + 81 * (MAXMESSAGES-1), msg, l);
  1684.   if (l < 80) memset(msgBuffer + 81 * (MAXMESSAGES-1) + l, ' ', 80 - l);
  1685.  
  1686.   // set new text and show bottom line
  1687.   XmTextSetString(msgText, msgBuffer);
  1688.   XmTextShowPosition(msgText, 81 * (MAXMESSAGES-1));
  1689. }
  1690.  
  1691. static int        thrustKey(KeySym k, int press)
  1692. {
  1693.   int level;
  1694.   switch (k) {
  1695.     case XK_0: level = 10; break;
  1696.     case XK_1: level = 1; break;
  1697.     case XK_2: level = 2; break;
  1698.     case XK_3: level = 3; break;
  1699.     case XK_4: level = 4; break;
  1700.     case XK_5: level = 5; break;
  1701.     case XK_6: level = 6; break;
  1702.     case XK_7: level = 7; break;
  1703.     case XK_8: level = 8; break;
  1704.     case XK_9: level = 9; break;
  1705.     case XK_grave: level = 0; break;        // reverse thrust
  1706.     default: return FALSE;            // not a thrust key
  1707.   }
  1708.  
  1709.   thrustKeyPressed[level] = press;
  1710.   for (int i = 10; i >= 0; i--)            // find highest thrust key
  1711.     if (thrustKeyPressed[i]) {            //  found one
  1712.       myShip->engineOutput(thrustLevel[i]);    //   set thrust level
  1713.       break;
  1714.     }
  1715.   if (i < 0) myShip->engineOutput(0.0);        // no thrust key pressed
  1716.  
  1717.   return TRUE;                    // it was a thrust key
  1718. }
  1719.  
  1720. int            keyEvent(XEvent* e)
  1721. {
  1722.   // get system independent key description
  1723.   KeySym k = XLookupKeysym(&(e->xkey), 0);
  1724.  
  1725.   // check if it's a thrust key ('`','1','2','3',...,'0')
  1726.   if (thrustKey(k, (e->xany.type == KeyPress))) return TRUE;
  1727.  
  1728.   // check for weapon select ('w')
  1729.   if (e->xany.type == KeyPress && (k == XK_W || k == XK_w)) {
  1730.     switch (currentWeapon()) {            // switch active weapon
  1731.       case Laser: currentWeapon(Missile); break;
  1732.       case Missile: currentWeapon(Laser); break;
  1733.     }
  1734.     return TRUE;
  1735.   }
  1736.  
  1737.   // check for next target ('t')
  1738.   if (e->xany.type == KeyPress && (k == XK_T || k == XK_t)) {
  1739.     nextTarget();
  1740.     return TRUE;
  1741.   }
  1742.  
  1743.   // check for frames per second activation ('/' or '?')
  1744.   if (e->xany.type == KeyPress && (k == XK_slash || k == XK_question)) {
  1745.     toggleFps();
  1746.     return TRUE;
  1747.   }
  1748.  
  1749.   // check for radar range change ('+' or '=' for up, '-' or '_' for down)
  1750.   if (e->xany.type == KeyPress && k == XK_equal) {
  1751.     increaseRange();
  1752.     return TRUE;
  1753.   }
  1754.   if (e->xany.type == KeyPress && k == XK_minus) {
  1755.     decreaseRange();
  1756.     return TRUE;
  1757.   }
  1758.  
  1759. #ifndef NORADIO
  1760.   // check for radio button pressed
  1761.   if (e->xany.type == KeyPress && (k == XK_r || k == XK_R)) {
  1762.     switch (radioState) {
  1763.       case RadioOff:
  1764.     XmToggleButtonGadgetSetState(radioToggle[1], TRUE, TRUE);
  1765.     break;
  1766.       case RadioTeam:
  1767.     XmToggleButtonGadgetSetState(radioToggle[2], TRUE, TRUE);
  1768.     break;
  1769.       case RadioAll:
  1770.     XmToggleButtonGadgetSetState(radioToggle[0], TRUE, TRUE);
  1771.     break;
  1772.     }
  1773.     return TRUE;
  1774.   }
  1775. #endif
  1776.  
  1777.   // check for sound button pressed
  1778.   if (e->xany.type == KeyPress && (k == XK_s || k == XK_S)) {
  1779.     switch (soundState) {
  1780.       case SoundOff:
  1781.     XmToggleButtonGadgetSetState(soundToggle[1], TRUE, TRUE);
  1782.     break;
  1783.       case SoundWarnings:
  1784.     XmToggleButtonGadgetSetState(soundToggle[2], TRUE, TRUE);
  1785.     break;
  1786.       case SoundAll:
  1787.     XmToggleButtonGadgetSetState(soundToggle[0], TRUE, TRUE);
  1788.     break;
  1789.     }
  1790.     return TRUE;
  1791.   }
  1792.  
  1793.   // check for help key (F1)
  1794.   if (e->xany.type == KeyPress && k == XK_F1) {
  1795.     showHelp();
  1796.     return TRUE;
  1797.   }
  1798.  
  1799.   // check for pause key ('p' or 'P')
  1800.   if (e->xany.type == KeyPress && (k == XK_p || k == XK_P)) {
  1801.     togglePauseGame();
  1802.     return TRUE;
  1803.   }
  1804.  
  1805.   // check for quit key (Esc)
  1806.   if (e->xany.type == KeyPress && k == XK_Escape) {
  1807.     quitGame();
  1808.     return TRUE;
  1809.   }
  1810.  
  1811.   // check for HUD color key ('h' or 'H')
  1812.   if (e->xany.type == KeyPress && (k == XK_h || k == XK_H)) {
  1813.     nextHudColor();
  1814.     return TRUE;
  1815.   }
  1816.  
  1817.   // check for space bar for restart
  1818.   if (e->xany.type == KeyPress && k == XK_space) {
  1819.     if (myShip->active() == ObjectInactive)
  1820.       restartSelf();
  1821.     else
  1822.       myShip->dropFlag();
  1823.     return TRUE;
  1824.   }
  1825.  
  1826.   // not one of my keys
  1827.   return FALSE;                    // let someone else use event
  1828. }
  1829.  
  1830. void            controlPanelAdvance(float dt)
  1831. {
  1832.   // update blink time
  1833.   blinkTime += dt;
  1834.   while (blinkTime > 1.0) blinkTime -= 1.0;    // 1 second period
  1835.   int blinked = FALSE;
  1836.   if (blinkOn && blinkTime > 0.75) {
  1837.     blinkTime -= 0.75;
  1838.     blinkOn = FALSE;
  1839.     blinked = TRUE;
  1840.   }
  1841.   else if (!blinkOn && blinkTime > 0.25) {
  1842.     blinkTime -= 0.25;
  1843.     blinkOn = TRUE;
  1844.     blinked = TRUE;
  1845.   }
  1846.  
  1847.   // if blinkOn changed draw appropriate areas
  1848.   if (blinked) {
  1849.     for (int i = ShipObject::FrontShield; i <= ShipObject::BottomShield; i++)
  1850.       if (int(20.0 * myShip->shipInfo().shieldStrength[i] + 0.5) == 0)
  1851.         oldShield[i] = -1;
  1852.     shieldsChanged();
  1853.   }
  1854.  
  1855.   // draw radar
  1856.   drawRadar(&radarSize, TRUE);
  1857.  
  1858.   if (currentTarget() != -1) targetChanged();
  1859. }
  1860.  
  1861. void            controlPanelReset()
  1862. {
  1863.   // reset time dependant stuff (like blink time)
  1864.   blinkTime = 0.0;
  1865.   blinkOn = TRUE;
  1866.  
  1867.   // set old states to bogus values so they'll get updated
  1868.   for (int i = ShipObject::FrontShield; i <= ShipObject::BottomShield; i++)
  1869.     oldShield[i] = -1;
  1870.   oldLaser = -1;
  1871.   oldMissile = -1;
  1872.   oldThrust = -20;
  1873.   oldFuel = -1;
  1874.   oldTarget = myShip;                // impossible target
  1875.  
  1876.   // clear keyboard state
  1877.   for (i = 0; i <= 10; i++) {
  1878.     thrustKeyPressed[i] = FALSE;
  1879.     thrustLevel[i] = (float)i / 10.0;
  1880.   }
  1881.   thrustLevel[0] = -0.25;
  1882.  
  1883.   // fill in other state info
  1884.   weaponChanged();
  1885.   laserChanged();
  1886.   missileChanged();
  1887.   thrustChanged();
  1888.   fuelChanged();
  1889.   shieldsChanged();
  1890.   targetChanged();
  1891.   scoreChanged();
  1892.   playersChanged();
  1893.   flagChanged();
  1894.   drawTeamColor(&colorSize, TRUE);
  1895. }
  1896.